
#include <BStyle>
#include <BLabel>
#include <BGridLayout>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BStackLayout>
#include <BDockLayout>

#include "DesktopDialog.h"

DesktopDialog::DesktopDialog(BWidget* parent) : BDialog(parent)
{
	_colorDialog = new BColorDialog();
	{
		BHBoxLayout* hlayout = (BHBoxLayout*)_colorDialog->layout(Part_Bottom);
		_textModeButton = new BButton("mode");
		_textModeButton->setCheckable(true);
		_textModeButton->setText("RGBA", false);
		_textModeButton->setText("HEX", true);

		_colorTextEdit = new BLineEdit();
		hlayout->insertWidget(0, _textModeButton);
		hlayout->insertWidget(1, _colorTextEdit);

		connect(_colorDialog, Signal_ColorChanged, &DesktopDialog::slotColorDialogColorChanged);
		connect(_colorTextEdit, Signal_EditFinished, &DesktopDialog::slotColorTextEditFinished);
	}

	BGridLayout* gridLayout = new BGridLayout();
	{
		_topSpinBox = new BRealSpinBox();
		_topSlider = new BSlider();
		_topSlider->setGraph(Graph_Circle_Fill);

		_leftSpinBox = new BRealSpinBox();
		_leftSlider = new BLongSlider();
		_leftSlider->setGraph(Graph_Circle_Fill);

		_colorButton = new BButton(Graph_Square_Fill);

		_rightSpinBox = new BRealSpinBox();
		_rightSlider = new BFloatSlider();
		_rightSlider->setIcon(new BIcon("./icon/ic_unusual_mini.png"));

		_bottomSpinBox = new BRealSpinBox();
		_bottomSlider = new BDoubleSlider();
		_bottomSlider->setIcon(new BIcon("./icon/ic_unusual_mini.png"));

		_topSpinBox->setAlign(Align_Center);
		_leftSpinBox->setAlign(Align_Center);
		_rightSpinBox->setAlign(Align_Center);
		_bottomSpinBox->setAlign(Align_Center);

		gridLayout->addWidget(0, 1, _topSpinBox);
		gridLayout->addWidget(1, 1, _topSlider);
		gridLayout->addWidget(2, 0, _leftSpinBox);
		gridLayout->addWidget(3, 0, _leftSlider);
		gridLayout->addWidget(2, 1, _colorButton);
		gridLayout->addWidget(2, 2, _rightSpinBox);
		gridLayout->addWidget(3, 2, _rightSlider);
		gridLayout->addWidget(4, 1, _bottomSpinBox);
		gridLayout->addWidget(5, 1, _bottomSlider);
		//gridLayout->addSpring(1, 1);
	}

	BHBoxLayout* colorLayout = new BHBoxLayout();
	{
		_colorComboBox = new BComboBox();
		_colorComboBox->setMaxShowCount(6);

		colorLayout->addWidget(new BLabel("color"));
		colorLayout->addWidget(_colorComboBox, 5);
	}

	BGridLayout* alignLayout = new BGridLayout("align");
	alignLayout->setMargin(5);
	alignLayout->setColumnCount(3);
	alignLayout->setRowCount(3);
	{
		BButton* leftTopButton = new BButton(Form_IconAlone, "left-top");			leftTopButton->setAsset(Align_LeftTop);
		BButton* rightTopButton = new BButton(Form_IconAlone, "right-top");			rightTopButton->setAsset(Align_RightTop);
		BButton* leftBottomButton = new BButton(Form_IconAlone, "left-bottom");		leftBottomButton->setAsset(Align_LeftBottom);
		BButton* rightBottomButton = new BButton(Form_IconAlone, "right-bottom");	rightBottomButton->setAsset(Align_RightBottom);

		BButton* leftButton = new BButton(Form_IconAlone, "left");			leftButton->setAsset(Align_LeftCenter);
		BButton* topButton = new BButton(Form_IconAlone, "top");			topButton->setAsset(Align_TopCenter);
		BButton* rightButton = new BButton(Form_IconAlone, "right");		rightButton->setAsset(Align_RightCenter);
		BButton* bottomButton = new BButton(Form_IconAlone, "bottom");		bottomButton->setAsset(Align_BottomCenter);

		BButton* centerButton = new BButton(Form_IconAlone, "center");		centerButton->setAsset(Align_Center);

		alignLayout->setWidget(0, 0, leftTopButton);
		alignLayout->setWidget(0, 2, rightTopButton);
		alignLayout->setWidget(2, 0, leftBottomButton);
		alignLayout->setWidget(2, 2, rightBottomButton);

		alignLayout->setWidget(0, 1, topButton);
		alignLayout->setWidget(1, 0, leftButton);
		alignLayout->setWidget(1, 2, rightButton);
		alignLayout->setWidget(2, 1, bottomButton);

		alignLayout->setWidget(1, 1, centerButton);

		_buttonGroup = new BButtonGroup();

		_buttonGroup->addButton(leftTopButton);
		_buttonGroup->addButton(rightTopButton);
		_buttonGroup->addButton(leftBottomButton);
		_buttonGroup->addButton(rightBottomButton);

		_buttonGroup->addButton(leftButton);
		_buttonGroup->addButton(topButton);
		_buttonGroup->addButton(rightButton);
		_buttonGroup->addButton(bottomButton);

		_buttonGroup->addButton(centerButton);

	}

	BHBoxLayout* stretchLayout = new BHBoxLayout();
	stretchLayout->setSpacing(2);
	{
		_widthStretchSpinBox = new BFloatSpinBox();
		_heightStretchSpinBox = new BFloatSpinBox();
		stretchLayout->addWidget(new BLabel("stretch"));
		stretchLayout->addWidget(_widthStretchSpinBox);
		stretchLayout->addWidget(_heightStretchSpinBox);
	}

	BHBoxLayout* buttonLayout = new BHBoxLayout();
	{
		_okButton = new BButton("OK");
		_cancelButton = new BButton("Cancel");
		buttonLayout->addWidget(_okButton);
		buttonLayout->addSpring();
		buttonLayout->addWidget(_cancelButton);
	}

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addLayout(gridLayout);
	vlayout->addLayout(colorLayout);
	vlayout->addLayout(alignLayout);
	vlayout->addLayout(stretchLayout);
	vlayout->addLayout(buttonLayout);

	connect(this, Signal_AssetChanged, &DesktopDialog::slotAssetChanged);

	connect(_topSpinBox, Signal_ValueChanged, &DesktopDialog::slotTopSpinBoxValueChanged);
	connect(_topSpinBox, Signal_EditFinished, &DesktopDialog::slotTopSpinBoxEditFinished);
	connect(_topSlider, Signal_Sliding, &DesktopDialog::slotTopSliding);

	connect(_leftSpinBox, Signal_ValueChanged, &DesktopDialog::slotLeftSpinBoxValueChanged);
	connect(_leftSpinBox, Signal_EditFinished, &DesktopDialog::slotLeftSpinBoxEditFinished);
	connect(_leftSlider, Signal_Sliding, &DesktopDialog::slotLeftSliding);

	connect(_rightSpinBox, Signal_ValueChanged, &DesktopDialog::slotRightSpinBoxValueChanged);
	connect(_rightSpinBox, Signal_EditFinished, &DesktopDialog::slotRightSpinBoxEditFinished);
	connect(_rightSlider, Signal_Sliding, &DesktopDialog::slotRightSliding);

	connect(_bottomSpinBox, Signal_ValueChanged, &DesktopDialog::slotBottomSpinBoxValueChanged);
	connect(_bottomSpinBox, Signal_EditFinished, &DesktopDialog::slotBottomSpinBoxEditFinished);
	connect(_bottomSlider, Signal_Sliding, &DesktopDialog::slotBottomSliding);

	connect(_colorButton, Signal_Clicked, &DesktopDialog::slotColorButtonClicked);
	connect(_colorComboBox, Signal_ItemClicked, &DesktopDialog::slotColorComboItemClicked);

	connect(_widthStretchSpinBox, Signal_EditFinished, &DesktopDialog::slotStretchEditFinished);
	connect(_heightStretchSpinBox, Signal_EditFinished, &DesktopDialog::slotStretchEditFinished);
	connect(_buttonGroup, Signal_Toggled, &DesktopDialog::slotAlignGroupToggled);

	connect(_okButton, Signal_Clicked, &DesktopDialog::slotOkButtonClicked);
	connect(_cancelButton, Signal_Clicked, &DesktopDialog::slotCancelButtonClicked);
}
DesktopDialog::~DesktopDialog()
{

}

BPerch DesktopDialog::getPerch()
{
	BPerch perch;
	perch.top() = (int)_topSpinBox->value();
	perch.left() = (int)_leftSpinBox->value();
	perch.right() = (int)_rightSpinBox->value();
	perch.bottom() = (int)_bottomSpinBox->value();
	return perch;
}

void DesktopDialog::slotAssetChanged()
{
	if (BWidget* widget = this->asset())
	{
		BPerch perch = widget->perch();
		_topSpinBox->setValue(perch.top());
		_leftSpinBox->setValue(perch.left());
		_rightSpinBox->setValue(perch.right());
		_bottomSpinBox->setValue(perch.bottom());

		if (BGridLayout* gridLayout = widget->query("upper-layout"))
		{
			Align align = gridLayout->align(widget);
			BButton* button = _buttonGroup->buttonOfAsset(align);
			button->setChecked(true);

			BSizeStretch stretch = gridLayout->stretch(widget);
			_widthStretchSpinBox->setValue(stretch.widthStretch());
			_heightStretchSpinBox->setValue(stretch.heightStretch());
		}

		BStyle* style = widget->style();
		if (!style)
		{
			style = new BStyle();
			widget->setStyle(style);
		}
		const BColor& color = style->color(Color_Background);
		_colorButton->setColor(color);
	}
}

void DesktopDialog::slotTopSpinBoxValueChanged(BObject* object, const BValue& value)
{
	if (BWidget* widget = this->asset())
	{
		BReal top = value;
		widget->setPerch(Part_Top, (int)top);
	}
}
void DesktopDialog::slotTopSpinBoxEditFinished(BObject* object, const BValue& value)
{
	BReal top = value;
	_topSlider->setValue((int)top);
}
void DesktopDialog::slotTopSliding(BObject* object, const BValue& value)
{
	int top = value;
	_topSpinBox->setValue(top);
}

void DesktopDialog::slotLeftSpinBoxValueChanged(BObject* object, const BValue& value)
{
	if (BWidget* widget = this->asset())
	{
		BReal left = value;
		widget->setPerch(Part_Left, (int)left);
	}
}
void DesktopDialog::slotLeftSpinBoxEditFinished(BObject* object, const BValue& value)
{
	BReal left = value;
	_leftSlider->setValue((BLong)left);
}
void DesktopDialog::slotLeftSliding(BObject* object, const BValue& value)
{
	BLong top = value;
	_leftSpinBox->setValue((BReal)top);
}

void DesktopDialog::slotRightSpinBoxValueChanged(BObject* object, const BValue& value)
{
	if (BWidget* widget = this->asset())
	{
		BReal right = value;
		widget->setPerch(Part_Right, (int)right);
	}
}
void DesktopDialog::slotRightSpinBoxEditFinished(BObject* object, const BValue& value)
{
	BReal right = value;
	_rightSlider->setValue((float)right);
}
void DesktopDialog::slotRightSliding(BObject* object, const BValue& value)
{
	float right = value;
	_rightSpinBox->setValue((BReal)right);
}

void DesktopDialog::slotBottomSpinBoxValueChanged(BObject* object, const BValue& value)
{
	if (BWidget* widget = this->asset())
	{
		BReal bottom = value;
		widget->setPerch(Part_Bottom, (int)bottom);
	}
}
void DesktopDialog::slotBottomSpinBoxEditFinished(BObject* object, const BValue& value)
{
	BReal bottom = value;
	_bottomSlider->setValue((double)bottom);
}
void DesktopDialog::slotBottomSliding(BObject* object, const BValue& value)
{
	double bottom = value;
	_bottomSpinBox->setValue((BReal)bottom);
}

void DesktopDialog::slotColorDialogColorChanged(BObject* object, const BValue& value)
{
	const BColor& color = value;
	const BString& textMode = _textModeButton->text(_textModeButton->checked());
	BString text;
	if (textMode == "RGBA")
	{
		text << color.r() << ',' << color.g() << ',' << color.b() << ',' << color.a();
	}
	else if (textMode == "HEX")
	{
		char cstr_r[4];		bByteToHex(cstr_r, color.r());
		char cstr_g[4];		bByteToHex(cstr_g, color.g());
		char cstr_b[4];		bByteToHex(cstr_b, color.b());
		char cstr_a[4];		bByteToHex(cstr_a, color.a());
		text << '#' << cstr_r << cstr_g << cstr_b << cstr_a;
	}
	_colorTextEdit->setText(text);
}
void DesktopDialog::slotColorTextEditFinished(BObject* object, const BValue& value)
{
	BString text = value;
	if (text.beginWith('#'))
	{
		text.remove(0);
		BByte r = bHexToByte(text.cstr() + 0);
		BByte g = bHexToByte(text.cstr() + 2);
		BByte b = bHexToByte(text.cstr() + 4);
		BByte a = bHexToByte(text.cstr() + 6);
		_colorDialog->setColor(r, g, b, a);
	}
	else
	{
		BStringArray words = text.split(',');
		if (words.size() == 4)
		{
			BByte r = words(0).toInt();
			BByte g = words(1).toInt();
			BByte b = words(2).toInt();
			BByte a = words(3).toInt();
			_colorDialog->setColor(r, g, b, a);
		}
	}
}

void DesktopDialog::slotColorButtonClicked(BObject* object, const BValue& value)
{
	if (BWidget* widget = this->asset())
	{
		_colorDialog->setTitle("Choose background");
		_colorDialog->setColor(_colorButton->color());
		if (_colorDialog->execute())
		{
			const BColor& color = _colorDialog->color();
			_colorButton->setColor(color);

			BStyle* style = widget->style();

			style->setColor(StyleColor(Color_Background + State_None), color);
			style->setColor(StyleColor(Color_Background + State_Normal), color);
			style->setColor(StyleColor(Color_Background + State_Normal_Hovered), color);
			style->setColor(StyleColor(Color_Background + State_Normal_Pressed), color);
			style->setColor(StyleColor(Color_Background + State_Normal_Selected), color);

			widget->setStyle(style);
		}
	}
}
void DesktopDialog::slotColorComboItemClicked(BObject* object, const BValue& value)
{
	if (BWidget* widget = this->asset())
	{
		if (BComboItem* item = value)
		{
			const BColor& color = item->value();
			_colorButton->setColor(color);

			BStyle* style = widget->style();

			style->setColor(StyleColor(Color_Background + State_None), color);
			style->setColor(StyleColor(Color_Background + State_Normal), color);
			style->setColor(StyleColor(Color_Background + State_Normal_Hovered), color);
			style->setColor(StyleColor(Color_Background + State_Normal_Pressed), color);
			style->setColor(StyleColor(Color_Background + State_Normal_Selected), color);

			widget->setStyle(style);
		}
	}
}
void DesktopDialog::slotStretchEditFinished(BObject* object, const BValue& value)
{
	float widthStretch = _widthStretchSpinBox->value();
	float heightStretch = _heightStretchSpinBox->value();
	if (BWidget* widget = this->asset())
	{
		if (BGridLayout* gridLayout = widget->query("upper-layout"))
		{
			gridLayout->setStretch(widget, BSizeStretch(widthStretch, heightStretch));
		}
		if (BDockLayout* dockLayout = widget->query("upper-layout"))
		{
			dockLayout->setStretch(widget, BSizeStretch(widthStretch, heightStretch));
		}
	}
}
void DesktopDialog::slotAlignGroupToggled(BButtonGroup* buttonGroup, const BValue& value)
{
	if (BButton* button = buttonGroup->checkedButton())
	{
		Align align = button->asset();
		if (BWidget* widget = this->asset())
		{
			if (BGridLayout* gridLayout = widget->query("upper-layout"))
			{
				gridLayout->setAlign(widget, align);
			}
			if (BStackLayout* stackLayout = widget->query("upper-layout"))
			{
				stackLayout->setAlign(widget, align);
			}
			if (BDockLayout* dockLayout = widget->query("upper-layout"))
			{
				dockLayout->setAlign(widget, align);
			}
		}
	}
}

void DesktopDialog::slotOkButtonClicked()
{
	this->setResult(true);
	this->close(true);
}
void DesktopDialog::slotCancelButtonClicked()
{
	this->close(false);
}

void DesktopDialog::styleEvent(const BEvent& event)
{
	BDialog::styleEvent(event);
	const BStyle* style = event.value();
	for (int i = 0; i < _buttonGroup->buttonCount(); i++)
	{
		BButton* button = _buttonGroup->button(i);
		button->setFixedSize(56);
		button->setSizePolicy(Policy_Fixed);
		button->setIcon(style->icon(button->text()));
	}
	if (_colorComboBox->itemCount() == 0)
	{
		BStringArray colorNames;
		style->colorNames(colorNames);
		for (int i = 0; i < colorNames.size(); i++)
		{
			const BString& name = colorNames[i];
			const BColor& color = style->color(name);
			_colorComboBox->addItem(Graph_Circle_Fill, name, color)->setColor(color);
		}
	}
}
